"""
MariaDB数据库备份模块

提供MariaDB数据库的备份功能，支持数据导出和结构备份。
"""

import os
import subprocess
import tempfile
import pymysql
from typing import List, Dict, Any, Optional
from ..core import DatabaseBackup


class MariaDBBackup(DatabaseBackup):
    """MariaDB数据库备份类
    
    实现MariaDB数据库的备份功能。MariaDB与MySQL兼容，
    但提供了一些额外的特性和优化。
    """
    
    def __init__(self, host: str, port: int, username: str, password: str, 
                 database: str, backup_dir: str = "backups",
                 mysqldump_path: str = "mysqldump"):
        """初始化MariaDB备份实例
        
        参数:
            host (str): MariaDB主机地址
                示例值: "localhost"
            port (int): MariaDB端口
                示例值: 3306
            username (str): MariaDB用户名
                示例值: "root"
            password (str): MariaDB密码
                示例值: "password123"
            database (str): 数据库名称
                示例值: "my_database"
            backup_dir (str): 备份文件存储目录
                示例值: "backups"
            mysqldump_path (str): mysqldump命令路径
                示例值: "mysqldump"
        
        返回:
            MariaDBBackup: MariaDB备份实例
        """
        super().__init__(host, port, username, password, database, backup_dir)
        self.mysqldump_path = mysqldump_path
        self.connection = None
    
    def connect(self) -> bool:
        """连接到MariaDB数据库
        
        返回:
            bool: 连接是否成功
                示例值: True
        """
        try:
            self.connection = pymysql.connect(
                host=self.host,
                port=self.port,
                user=self.username,
                password=self.password,
                database=self.database,
                charset='utf8mb4'
            )
            self.logger.info(f"成功连接到MariaDB数据库 {self.database}")
            return True
        except Exception as e:
            self.logger.error(f"连接MariaDB数据库失败: {e}")
            return False
    
    def disconnect(self) -> bool:
        """断开MariaDB数据库连接
        
        返回:
            bool: 断开是否成功
                示例值: True
        """
        try:
            if self.connection:
                self.connection.close()
                self.connection = None
                self.logger.info("已断开MariaDB数据库连接")
            return True
        except Exception as e:
            self.logger.error(f"断开MariaDB数据库连接失败: {e}")
            return False
    
    def get_tables(self) -> List[str]:
        """获取MariaDB数据库中的所有表名
        
        返回:
            List[str]: 表名列表
                示例值: ["users", "products", "orders"]
        """
        if not self.connection:
            self.logger.error("数据库未连接")
            return []
        
        try:
            with self.connection.cursor() as cursor:
                cursor.execute("SHOW TABLES")
                tables = [row[0] for row in cursor.fetchall()]
                self.logger.info(f"获取到 {len(tables)} 个表")
                return tables
        except Exception as e:
            self.logger.error(f"获取表列表失败: {e}")
            return []
    
    def backup_table(self, table_name: str, output_file: str, 
                    include_data: bool = True) -> bool:
        """备份单个MariaDB数据表
        
        参数:
            table_name (str): 表名
                示例值: "users"
            output_file (str): 输出文件路径
                示例值: "backups/users_20231201.sql"
            include_data (bool): 是否包含数据
                示例值: True
        
        返回:
            bool: 备份是否成功
                示例值: True
        """
        try:
            # 构建mysqldump命令（MariaDB兼容MySQL语法）
            cmd = [
                self.mysqldump_path,
                f"-h{self.host}",
                f"-P{self.port}",
                f"-u{self.username}",
                f"-p{self.password}",
                self.database,
                table_name
            ]
            
            # 添加MariaDB特定优化参数
            cmd.extend([
                "--single-transaction",
                "--quick",
                "--skip-lock-tables"
            ])
            
            # 如果不包含数据，只备份结构
            if not include_data:
                cmd.append("--no-data")
            
            # 执行备份命令
            with open(output_file, 'w', encoding='utf-8') as f:
                result = subprocess.run(cmd, stdout=f, stderr=subprocess.PIPE, 
                                      text=True, timeout=300)
            
            if result.returncode == 0:
                self.logger.info(f"成功备份表 {table_name} 到 {output_file}")
                return True
            else:
                self.logger.error(f"备份表 {table_name} 失败: {result.stderr}")
                return False
                
        except subprocess.TimeoutExpired:
            self.logger.error(f"备份表 {table_name} 超时")
            return False
        except Exception as e:
            self.logger.error(f"备份表 {table_name} 时发生错误: {e}")
            return False
    
    def backup_database(self, output_file: str, include_data: bool = True,
                       tables: Optional[List[str]] = None) -> Dict[str, Any]:
        """备份整个MariaDB数据库
        
        参数:
            output_file (str): 输出文件路径
                示例值: "backups/full_backup_20231201.sql"
            include_data (bool): 是否包含数据
                示例值: True
            tables (Optional[List[str]]): 指定要备份的表（None表示备份所有表）
                示例值: ["users", "products"]
        
        返回:
            Dict[str, Any]: 备份结果信息
                示例值: {
                    "success": True,
                    "output_file": "backups/full_backup_20231201.sql",
                    "tables_backed_up": 10,
                    "file_size": "15.2MB"
                }
        """
        try:
            # 构建mysqldump命令（MariaDB优化）
            cmd = [
                self.mysqldump_path,
                f"-h{self.host}",
                f"-P{self.port}",
                f"-u{self.username}",
                f"-p{self.password}",
                "--single-transaction",
                "--quick",
                "--skip-lock-tables",
                "--routines",
                "--triggers",
                "--events",
                self.database
            ]
            
            # 添加MariaDB特定参数
            cmd.extend([
                "--master-data=2",  # 记录二进制日志位置
                "--flush-logs"      # 刷新日志文件
            ])
            
            # 如果不包含数据，只备份结构
            if not include_data:
                cmd.append("--no-data")
            
            # 如果指定了表，只备份这些表
            if tables:
                cmd.extend(tables)
            
            # 执行备份命令
            with open(output_file, 'w', encoding='utf-8') as f:
                result = subprocess.run(cmd, stdout=f, stderr=subprocess.PIPE, 
                                      text=True, timeout=1800)  # 30分钟超时
            
            if result.returncode == 0:
                file_size = os.path.getsize(output_file)
                file_size_str = self._format_file_size(file_size)
                
                result_info = {
                    "success": True,
                    "output_file": output_file,
                    "file_size": file_size_str,
                    "tables_backed_up": len(tables) if tables else "all"
                }
                
                self.logger.info(f"成功备份数据库 {self.database} 到 {output_file}")
                return result_info
            else:
                self.logger.error(f"备份数据库失败: {result.stderr}")
                return {
                    "success": False,
                    "error": result.stderr
                }
                
        except subprocess.TimeoutExpired:
            self.logger.error("备份数据库超时")
            return {
                "success": False,
                "error": "备份操作超时"
            }
        except Exception as e:
            self.logger.error(f"备份数据库时发生错误: {e}")
            return {
                "success": False,
                "error": str(e)
            }
    
    def test_connection(self) -> Dict[str, Any]:
        """测试数据库连接
        
        返回:
            Dict[str, Any]: 连接测试结果
                示例值: {
                    "success": True,
                    "database_version": "10.11.4-MariaDB",
                    "connection_info": {
                        "host": "localhost",
                        "port": 3306,
                        "database": "my_database"
                    }
                }
        """
        try:
            if not self.connect():
                return {
                    "success": False,
                    "error": "连接失败"
                }
            
            with self.connection.cursor() as cursor:
                cursor.execute("SELECT VERSION()")
                version = cursor.fetchone()[0]
                
                cursor.execute("SELECT DATABASE()")
                current_db = cursor.fetchone()[0]
            
            result = {
                "success": True,
                "database_version": version,
                "current_database": current_db,
                "connection_info": {
                    "host": self.host,
                    "port": self.port,
                    "database": self.database
                }
            }
            
            self.disconnect()
            return result
            
        except Exception as e:
            return {
                "success": False,
                "error": str(e)
            }
    
    def get_database_info(self) -> Dict[str, Any]:
        """获取数据库详细信息
        
        返回:
            Dict[str, Any]: 数据库信息
                示例值: {
                    "tables_count": 15,
                    "total_size": "256MB",
                    "character_set": "utf8mb4",
                    "collation": "utf8mb4_general_ci",
                    "engine": "InnoDB"
                }
        """
        if not self.connect():
            return {
                "tables_count": 0,
                "total_size": "0B",
                "error": "连接失败"
            }
        
        try:
            with self.connection.cursor() as cursor:
                # 获取表数量
                cursor.execute("SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = %s", 
                             (self.database,))
                tables_count = cursor.fetchone()[0]
                
                # 获取数据库大小
                cursor.execute("""
                    SELECT SUM(data_length + index_length) 
                    FROM information_schema.tables 
                    WHERE table_schema = %s
                """, (self.database,))
                total_size_bytes = cursor.fetchone()[0] or 0
                
                # 获取字符集和排序规则
                cursor.execute("""
                    SELECT DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME
                    FROM information_schema.SCHEMATA 
                    WHERE SCHEMA_NAME = %s
                """, (self.database,))
                charset_info = cursor.fetchone()
                
                # 获取存储引擎信息
                cursor.execute("""
                    SELECT ENGINE, COUNT(*) 
                    FROM information_schema.TABLES 
                    WHERE TABLE_SCHEMA = %s 
                    GROUP BY ENGINE
                """, (self.database,))
                engine_info = cursor.fetchall()
                
            result = {
                "tables_count": tables_count,
                "total_size": self._format_file_size(total_size_bytes),
                "character_set": charset_info[0] if charset_info else "unknown",
                "collation": charset_info[1] if charset_info else "unknown",
                "engines": dict(engine_info) if engine_info else {}
            }
            
            self.disconnect()
            return result
            
        except Exception as e:
            self.logger.error(f"获取数据库信息失败: {e}")
            return {
                "tables_count": 0,
                "total_size": "0B",
                "error": str(e)
            }
    
    def backup_with_compression(self, output_file: str, 
                               compression: str = "gzip") -> Dict[str, Any]:
        """使用压缩备份数据库
        
        参数:
            output_file (str): 输出文件路径
                示例值: "backups/compressed_backup_20231201.sql.gz"
            compression (str): 压缩方式（gzip, bzip2, xz）
                示例值: "gzip"
        
        返回:
            Dict[str, Any]: 备份结果信息
                示例值: {
                    "success": True,
                    "output_file": "backups/compressed_backup_20231201.sql.gz",
                    "compression_ratio": "75%",
                    "original_size": "20MB",
                    "compressed_size": "5MB"
                }
        """
        try:
            # 构建压缩备份命令
            cmd = [
                self.mysqldump_path,
                f"-h{self.host}",
                f"-P{self.port}",
                f"-u{self.username}",
                f"-p{self.password}",
                "--single-transaction",
                "--quick",
                self.database
            ]
            
            # 根据压缩方式选择压缩命令
            if compression == "gzip":
                compress_cmd = ["gzip"]
                output_file += ".gz"
            elif compression == "bzip2":
                compress_cmd = ["bzip2"]
                output_file += ".bz2"
            elif compression == "xz":
                compress_cmd = ["xz"]
                output_file += ".xz"
            else:
                return {
                    "success": False,
                    "error": f"不支持的压缩方式: {compression}"
                }
            
            # 执行备份并压缩
            with open(output_file, 'wb') as f:
                dump_process = subprocess.Popen(cmd, stdout=subprocess.PIPE, 
                                              stderr=subprocess.PIPE)
                compress_process = subprocess.Popen(compress_cmd, 
                                                  stdin=dump_process.stdout,
                                                  stdout=f)
                
                dump_process.stdout.close()
                dump_process.wait()
                compress_process.wait()
            
            if dump_process.returncode == 0 and compress_process.returncode == 0:
                file_size = os.path.getsize(output_file)
                file_size_str = self._format_file_size(file_size)
                
                result_info = {
                    "success": True,
                    "output_file": output_file,
                    "compression": compression,
                    "compressed_size": file_size_str
                }
                
                self.logger.info(f"成功压缩备份数据库到 {output_file}")
                return result_info
            else:
                error_msg = dump_process.stderr.read().decode() if dump_process.stderr else ""
                self.logger.error(f"压缩备份失败: {error_msg}")
                return {
                    "success": False,
                    "error": error_msg
                }
                
        except Exception as e:
            self.logger.error(f"压缩备份时发生错误: {e}")
            return {
                "success": False,
                "error": str(e)
            }
    
    def get_mariadb_specific_info(self) -> Dict[str, Any]:
        """获取MariaDB特定信息
        
        返回:
            Dict[str, Any]: MariaDB特定信息
                示例值: {
                    "version": "10.11.4-MariaDB",
                    "storage_engines": ["InnoDB", "Aria", "MyISAM"],
                    "plugins": ["auth_socket", "metadata_lock_info"],
                    "features": ["GIS", "JSON", "Window Functions"]
                }
        """
        if not self.connect():
            return {"error": "连接失败"}
        
        try:
            with self.connection.cursor() as cursor:
                # 获取存储引擎列表
                cursor.execute("SHOW ENGINES")
                engines = [row[0] for row in cursor.fetchall() if row[1] in ['YES', 'DEFAULT']]
                
                # 获取插件列表
                cursor.execute("SHOW PLUGINS")
                plugins = [row[0] for row in cursor.fetchall() if row[1] == 'ACTIVE']
                
                # 获取版本和特性
                cursor.execute("SELECT VERSION()")
                version = cursor.fetchone()[0]
                
            result = {
                "version": version,
                "storage_engines": engines,
                "plugins": plugins,
                "features": ["GIS", "JSON", "Window Functions", "CTE"]  # MariaDB常见特性
            }
            
            self.disconnect()
            return result
            
        except Exception as e:
            self.logger.error(f"获取MariaDB特定信息失败: {e}")
            return {"error": str(e)}